
package controller;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Session;

import logic.beans.*;
import logic.dao.*;

public class SEISaudeDefaultFacade<E extends DBElementIF,ID extends Serializable> {
	private static final Map<Class<?>,SEISaudeDefaultFacade<?,?>> singletonInstances = new HashMap<Class<?>,SEISaudeDefaultFacade<?,?>>();
	
	private AbstractDBElementDAO<E,ID> elementDAO;
	
	@SuppressWarnings("unchecked")
	public static <E extends DBElementIF,ID extends Serializable> SEISaudeDefaultFacade<E,ID> getInstance(Class<E> key) {
		if (singletonInstances.get(key) == null) {
			singletonInstances.put(key,new SEISaudeDefaultFacade<E,ID>(key));
		}
		return (SEISaudeDefaultFacade<E,ID>)singletonInstances.get(key);
	}
	
	@SuppressWarnings("unchecked")
	private SEISaudeDefaultFacade(Class<E> typeClass) {
		if (typeClass.equals(Behavior.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new BehaviorDAO());
		} else if (typeClass.equals(Disease.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new DiseaseDAO());
		} else if (typeClass.equals(Drug.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new DrugDAO());
		} else if (typeClass.equals(Composition.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new CompositionDAO());
		} else if (typeClass.equals(Food.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new FoodDAO());
		} else if (typeClass.equals(FoodComponent.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new FoodComponentDAO());
		} else if (typeClass.equals(State.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new StateDAO());
		} else if (typeClass.equals(Symptom.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new SymptomDAO());
		} else if (typeClass.equals(Treatment.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new TreatmentDAO());
		} else if (typeClass.equals(User.class)) {
			this.elementDAO = (AbstractDBElementDAO<E,ID>)(new UserDAO());
		} else {
			this.elementDAO = null;
		}
	}
	
	public AbstractDBElementDAO<E,ID> getElementDAO() {
		return elementDAO;
	}
	
	public ID registerElement(E element) {
		Session session = setupSession(elementDAO);
		ID id = elementDAO.save(element);
		commitSession(session);
		
		return id;
	}
	
	public void removeElement(ID id) {
		Session session = setupSession(elementDAO);
		elementDAO.delete(id);
		commitSession(session);
	}
	
	public void removeElements(List<ID> idList) {
		Session session = setupSession(elementDAO);
		for (ID id : idList) {
			elementDAO.delete(id);
		}
		commitSession(session);
	}
	
	public void updateElement(ID id,E newElement) {
		Session session = setupSession(elementDAO);
		elementDAO.update(id,newElement);
		commitSession(session);
	}
	
	public List<E> getAllElements() {
		Session session = setupSession(elementDAO);
		List<E> allElements = elementDAO.retrieveAll();
		commitSession(session);
		
		return allElements;
	}
	
	public int getElementNumber() {
		return getAllElements().size();
	}
	
	public E getElementById(ID id) {
		Session session = setupSession(elementDAO);
		E result = elementDAO.retrieve(id);
		commitSession(session);
		
		return result;
	}
	
	public List<E> getElementsByExample(E example,List<String> excludeProperties) {
		Session session = setupSession(elementDAO);
		List<E> result = elementDAO.retrieveByExample(example,excludeProperties);
		commitSession(session);
		
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public E getNewElementCopy(E src) throws InstantiationException,IllegalAccessException {
		E result = ((Class<E>)src.getClass()).newInstance();
		getElementDAO().doUpdate(result,src);
		
		return result;
	}
	
	public boolean verifyAccount(String userName,String pass) {
		return verifyAccount(new User(userName,pass));
	}
	
	public boolean verifyAccount(User user) {
		UserDAO userDAO = new UserDAO();
		Session session = setupSession(userDAO);
		boolean result = userDAO.checkUser(user);
		commitSession(session);
		
		return result;
	}
	
	// Extras.
	
	public void clearCurrentSession() {
		getElementDAO().getCurrentSession().clear();
	}
	
	public void commitCurrentSession() {
		commitSession(getElementDAO().getCurrentSession());
	}
	
	private Session setupSession(AbstractDBElementDAO<?,?> dao) {
		Session session = dao.getCurrentSession();
		session.beginTransaction();
		
		return session;
	}
	
	private void commitSession(Session session) {
		session.getTransaction().commit();
	}
}
